package com.supreme.studyserver.component;

import com.supreme.common.constant.ConsoleColors;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
public class StudyApplicationRunner implements ApplicationRunner {

    @Resource
    private String userDir;

    @Resource
    private String environmentLog;

    @Resource
    private String beanNamesLog;

    @Resource
    private String javaJVMLog;

    @Value("${SERVER_INDEX}")
    private String envServerIndex;

    @Value("${SERVER_NODE_INDEX}")
    private String serverNodeIndex;

    @Resource
    private AnnotationConfigServletWebServerApplicationContext applicationContext;

    @Resource
    private BeanLifecycle qumBeanMan;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        ConsoleColors.printf(ConsoleColors.YELLOW_BOLD_BRIGHT, "StudyApplicationRunner = %s\n", args.toString());
        printEnvironment();
        printSpringBean();
        printShowJavaJVM();
    }

    private void printEnvironment() throws IOException {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();

        Path path = Paths.get(environmentLog);
        if (!Files.exists(path)) {
            Files.createFile(path);
        }

        List<String> recordList = new ArrayList<>();

        Map<String, Object> systemProperties = environment.getSystemProperties();
        recordList.add("========== SystemProperties ==========");
        recordList.addAll(
                systemProperties.entrySet().stream()
                        .map(stringObjectEntry -> stringObjectEntry.getKey() + ": " + stringObjectEntry.getValue().toString())
                        .collect(Collectors.toList())
        );

        Map<String, Object> systemEnvironment = environment.getSystemEnvironment();
        recordList.add("");
        recordList.add("========== SystemEnvironment ==========");
        recordList.addAll(
                systemEnvironment.entrySet().stream()
                        .map(stringObjectEntry -> stringObjectEntry.getKey() + ": " + stringObjectEntry.getValue().toString())
                        .collect(Collectors.toList())
        );

        MutablePropertySources mutablePropertySources = environment.getPropertySources();
        recordList.add("");
        recordList.add("========== MutablePropertySources ==========");
        recordList.add(mutablePropertySources.toString());

        recordList.add("");
        recordList.add("========== GetEnvironment ==========");
        Integer serverIndex = environment.getProperty("SERVER_INDEX", Integer.class, 0);
        Integer serverNodeIndex = environment.getProperty("SERVER_NODE_INDEX", Integer.class, 0);
        recordList.add("SERVER_INDEX: " + serverIndex);
        recordList.add("ENV_SERVER_INDEX: " + envServerIndex);
        recordList.add("SERVER_NODE_INDEX: " + serverNodeIndex);

        Files.write(path, recordList);
    }

    private void printSpringBean() throws IOException {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Boolean printBeanList = environment.getProperty("study.server.printBeanList", Boolean.class, false);
        if (printBeanList) {
            Path path = Paths.get(beanNamesLog);
            if (!Files.exists(path)) {
                Files.createFile(path);
            }
            Files.write(path, Stream.of(applicationContext.getBeanDefinitionNames()).collect(Collectors.toList()));
        }
    }

    public long toM(long value) {
        return value / 1024 / 1024;
    }

    private void printShowJavaJVM() throws IOException {
        Path path = Paths.get(javaJVMLog);
        if (!Files.exists(path)) {
            Files.createFile(path);
        }

        final Runtime runtime = Runtime.getRuntime();
        final long freeMemory = runtime.freeMemory();
        final long totalMemory = runtime.totalMemory();
        final long maxMemory = runtime.maxMemory();
        System.out.printf("[free: %dm] [total: %dm] [max: %dm]\n", freeMemory, totalMemory, maxMemory);

        long usableMemory = maxMemory - totalMemory + freeMemory;
        String[] strings = {
                "最大内存 maxMemory = " + toM(maxMemory),
                "已分配内存 totalMemory = " + toM(totalMemory),
                "已分配内存中的剩余空间 freeMemory = " + toM(freeMemory),
                "最大可用内存 usableMemory = " + toM(usableMemory)
        };
        Files.write(path, Stream.of(strings).collect(Collectors.toList()));
    }
}
